{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "16bb4bc3",
   "metadata": {},
   "source": [
    "##  Python REPL\n",
    "\n",
    "Python REPL（Read-Eval-Print Loop）是一个交互式编程环境，允许程序员立即执行代码并获取结果。REPL 这个术语来源于描述这种环境工作方式的四个步骤：\n",
    "\n",
    "- Read（读取） - 读取用户输入的代码。\n",
    "- Eval（求值） - 对输入的代码进行求值。\n",
    "- Print（打印） - 打印求值的结果。\n",
    "- Loop（循环） - 返回第一步，等待用户输入更多的代码。\n",
    "\n",
    "在 Python 中，REPL 通常是通过命令行工具 python 或 python3（取决于安装的 Python 版本）访问的。启动这个工具后，用户可以直接输入 Python 代码，并立即看到代码执行的结果。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "50b5ef2f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import Tool\n",
    "from langchain_experimental.utilities import PythonREPL\n",
    "\n",
    "python_repl = PythonREPL()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a424c0ca",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Python REPL can execute arbitrary code. Use with caution.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'4\\n'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "python_repl.run(\"print(1+3)\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "239f8449",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI, OpenAI\n",
    "\n",
    "openai_api_key = \"EMPTY\"\n",
    "openai_api_base = \"http://127.0.0.1:1234/v1\"\n",
    "model = ChatOpenAI(\n",
    "    openai_api_key=openai_api_key,\n",
    "    openai_api_base=openai_api_base,\n",
    "    temperature=0.1,\n",
    ")\n",
    "llm = model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "cf7b27ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "promptFormat = \"\"\"{query}\n",
    "\n",
    "请根据上面的问题，生成Python代码计算出问题的答案，最后计算出来的结果用print()打印出来，请直接返回Python代码，不要返回其他任何内容的字符串\n",
    "\"\"\"\n",
    "prompt = ChatPromptTemplate.from_template(promptFormat)\n",
    "output_parser = StrOutputParser()\n",
    "\n",
    "chain = prompt | llm | output_parser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "f42641ca",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'```python\\n# 计算每箱苹果的重量\\napples_per_box = 45 / 3\\n\\n# 每箱梨比每箱苹果多的重量\\nweight_difference = 5\\n\\n# 计算每箱梨的重量\\npears_per_box = apples_per_box + weight_difference\\n\\n# 计算3箱梨的总重量\\ntotal_pears = pears_per_box * 3\\n\\nprint(total_pears)\\n```'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result = chain.invoke({\"query\":\"3箱苹果重45千克。一箱梨比一箱苹果多5千克，3箱梨重多少千克？\"})\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "1b52c29d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def parsePython(codeStr):\n",
    "    codeStr = result.replace(\"```python\",\"\")\n",
    "    codeStr = result.replace(\"```\",\"\")\n",
    "    return codeStr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "78613221",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['query'], messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['query'], template='{query}\\n\\n请根据上面的问题，生成Python代码计算出问题的答案，最后计算出来的结果用print()打印出来，请直接返回Python代码，不要返回其他任何内容的字符串\\n'))])\n",
       "| ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x00000190FB262590>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x000001909EB85AE0>, temperature=0.1, openai_api_key=SecretStr('**********'), openai_api_base='http://127.0.0.1:1234/v1', openai_proxy='')\n",
       "| StrOutputParser()\n",
       "| RunnableLambda(parsePython)"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain = prompt | llm | output_parser | parsePython\n",
    "chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "ff670e4b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n# 计算每箱苹果的重量\\napples_per_box = 45 / 3\\n\\n# 每箱梨比每箱苹果多的重量\\nweight_difference = 5\\n\\n# 计算每箱梨的重量\\npears_per_box = apples_per_box + weight_difference\\n\\n# 计算3箱梨的总重量\\ntotal_pears = pears_per_box * 3\\n\\nprint(total_pears)\\n\\n40'"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result = chain.invoke({\"query\":\"3箱苹果重45千克。一箱梨比一箱苹果多5千克，3箱梨重多少千克？\"})\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "f838c3c0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'60.0\\n'"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "python_repl.run(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "ef22f667",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['query'], messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['query'], template='{query}\\n\\n请根据上面的问题，生成Python代码计算出问题的答案，最后计算出来的结果用print()打印出来，请直接返回Python代码，不要返回其他任何内容的字符串\\n'))])\n",
       "| ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x00000190FB262590>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x000001909EB85AE0>, temperature=0.1, openai_api_key=SecretStr('**********'), openai_api_base='http://127.0.0.1:1234/v1', openai_proxy='')\n",
       "| StrOutputParser()\n",
       "| RunnableLambda(parsePython)\n",
       "| RunnableLambda(run)"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain = prompt | llm | output_parser | parsePython | python_repl.run\n",
    "chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "464ffb51",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'60.0\\n'"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result = chain.invoke({\"query\":\"3箱苹果重45千克。一箱梨比一箱苹果多5千克，3箱梨重多少千克？\"})\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c9fd6524",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
